package com.tsd.common.service.impl;

import com.alibaba.fastjson.JSON;
import com.tsd.common.dao.CommonFileMapper;
import com.tsd.common.entity.CommonFile;
import com.tsd.common.entity.CommonFileExt;
import com.tsd.common.service.CommonFileService;
import com.tsd.core.config.Config;
import com.tsd.core.constants.ConfigKeyConstants;
import com.tsd.core.constants.Constants;
import com.tsd.core.datasource.DataSourceContextHolder;
import com.tsd.core.utils.*;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.PageBean;
import com.tsd.jwt.JwtRefreshUtil;
import com.tsd.service.BaseServiceImpl;
import com.tsd.storage.StorageService;
import com.tsd.system.entity.SysUser;
import com.tsd.system.entity.SysUserExt;
import com.tsd.system.utils.SysUtil;
import io.jsonwebtoken.Claims;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;

/**
 * 描述：CommonFile 服务实现层
 *
 * @author huawei
 * @date 2021/08/08 20:40:38
 */
@Service
public class CommonFileServiceImpl extends BaseServiceImpl implements CommonFileService {

    private static final Logger LOGGER = LoggerFactory.getLogger("quartzLogger");
    @Resource
    private CommonFileMapper commonFileMapper;
    @Resource
    private StorageService storageService;

    @Override
    public CommonFile getCommonFileById(Long id) throws Exception {
        return commonFileMapper.selectByPrimaryKey(id);
    }

    @Override
    public CommonFileExt queryBySid(String sid) throws Exception {
        return commonFileMapper.selectBySid(sid);
    }

    @Override
    public CommonFileExt queryExcelTemplateByBizSid(String bizSid) {
        return commonFileMapper.selectExcelTemplateByBizSid(bizSid);
    }

    @Override
    public void deleteCommonFiles(List<String> list, SysUser opUser) throws Exception {
        for (String sid : list) {
            CommonFileExt fi = commonFileMapper.selectBySid(sid);
            if (fi != null) {
                if (opUser != null && opUser.getSid().equals(fi.getOwner_sid())) {
                    if (fi.getState().intValue() == CommonFileExt.StateUsed) {
                        throw new HlpException("文件已被使用，不能删除");
                    }
                    commonFileMapper.deleteByPrimaryKey(fi.getId());
                    String path = fi.getFile_path();
                    FileUtil.delete(path);
                } else {
                    throw new HlpException("你无权删除该数据");
                }
            }
        }
    }

    @Override
    public void saveCommonFile(CommonFile record, SysUser opUser) throws Exception {
        File file = new File(record.getFile_path());
        String accountSetSid = DataSourceContextHolder.getDataSourceType();
        if ((record.getFile_len() == null || record.getFile_len() == 0L) && file.exists()) {
            record.setFile_len(file.length());
        }
        if (HlpUtils.isEmpty(record.getId())) {
            super.autoInjectBaseData(record, opUser, TYPE_CREATE);
            commonFileMapper.insertSelective(record);
            store2Oss(accountSetSid, record);
        } else {
            CommonFile old = commonFileMapper.selectBySid(record.getSid());
            if (old != null) {
                super.autoInjectBaseData(record, opUser, TYPE_UPDATE);
                commonFileMapper.updateByPrimaryKeySelective(record);
                if (!HlpUtils.isEqual(record.getFile_path(), old.getFile_path())) {
                    store2Oss(accountSetSid, record);
                }
            }
        }
    }

    private void store2Oss(String accountSetSid, CommonFile fi) {
        if (CommonFileExt.BIZ_TYPE_IMPORT.equalsIgnoreCase(fi.getBiz_type())) {
            //用于导入的临时文件不上传oss
            return;
        }
        if (!StorageService.STORE_TYPE_LOCAL.equals(storageService.getActive())) {
            if (FileUtil.isFileExist(fi.getFile_path())) {
                File file = new File(fi.getFile_path());
                FileInputStream inputStream = null;
                try {
                    inputStream = new FileInputStream(file);
                    String ext = FileUtil.getFileType(file.getName());
                    String url = storageService.store(inputStream, file.length(), FileUtil.getFileType(file.getName()), accountSetSid, fi.getSid() + ext);
                    fi.setOss_type(storageService.getActive());
                    fi.setOss_url(url);
                    commonFileMapper.updateByPrimaryKeySelective(fi);
                } catch (Exception e) {
                    LOGGER.error(ExceptionUtil.getStackTraceFromException(e));
                } finally {
                    FileUtil.safeCloseInputStrem(inputStream);
                }
            }
        }
    }

    @Override
    public List<CommonFileExt> findCommonFiles(Map<String, Object> params, PageBean page) throws Exception {
        return commonFileMapper.selectByPage(params, page);
    }

    @Override
    public List<CommonFileExt> findCommonFiles(Map<String, Object> params) throws Exception {
        return commonFileMapper.selectByParams(params);
    }

    @Override
    public CommonFileExt getFileInfoBySid(String sid) throws Exception {
        return commonFileMapper.selectBySid(sid);
    }

    @Override
    public void deleteFileInfo4Notused(String sids, SysUser opUser) throws Exception {
        String[] idList = sids.split(",");
        List<String> list = new ArrayList<>(Arrays.asList(idList));
        this.deleteCommonFiles(list, opUser);
    }

    @Override
    public List<CommonFileExt> getCommonFilesBySidList(List<String> sidList) throws Exception {
        return commonFileMapper.selectBySidList(sidList);
    }

    @Override
    public void saveAssociateData(CommonFile file) throws Exception {
        commonFileMapper.updateAssociateData(file);
    }

    @Override
    public void updateAssociateData(String ids, String biz_table, String biz_sid, String biz_field_tag, Double lat, Double lng) throws Exception {
        if (!HlpUtils.isEmpty(ids)) {
            List<CommonFile> files = JSON.parseArray(ids, CommonFile.class);
            for (CommonFile file : files) {
                if (!HlpUtils.isEmpty(file.getSid())) {
                    file.setAssociate_biz_table(biz_table);
                    file.setAssociate_biz_sid(biz_sid);
                    file.setAssociate_biz_field_tag(biz_field_tag);
                    file.setLng(lng);
                    file.setLat(lat);
                    saveAssociateData(file);
                }
            }
        }
    }

    @Override
    public void updateAssociateData(String file_sid, String biz_table, String biz_sid, String biz_field_tag) throws Exception {
        CommonFile file = commonFileMapper.selectBySid(file_sid);
        if (file != null) {
            file.setAssociate_biz_table(biz_table);
            file.setAssociate_biz_sid(biz_sid);
            file.setAssociate_biz_field_tag(biz_field_tag);
            saveAssociateData(file);
        }
    }

    @Override
    public List<CommonFile> getFileInfoByBizSidAndBizTable(String associate_biz_sid, String associate_biz_table) throws Exception {
        return commonFileMapper.getFileInfoByBizSidAndBizTable(associate_biz_sid, associate_biz_table);
    }

    @Override
    public void updateList(List<CommonFile> list) throws Exception {
        commonFileMapper.updateList(list);
    }

    @Override
    public void updateDrBySid(String sid) throws Exception {
        commonFileMapper.updateDrBySid(sid);
    }

    @Override
    public CommonFile genIconFile(String sid, Integer newWidth, SysUser opUser) throws Exception {
        CommonFile old = commonFileMapper.selectBySid(sid);
        if (old != null) {
            String path = old.getFile_path();
            if (FileUtil.isFileExist(path)) {
                if (FileUtil.isPictureFile(path)) {
                    String extWithDot = FileUtil.getFileType(path);
                    String newPath = path.substring(0, path.lastIndexOf(".")) + CommonFileExt.ICON_TAG + extWithDot;
                    if (newWidth == null) {
                        newWidth = 100;
                    }
                    ImageUtil.zoomImageScale(new File(path), newPath, newWidth);
                    old.setId(null);
                    old.setSid(null);
                    old.setFile_path(newPath);
                    saveCommonFile(old, opUser);
                    return old;
                }
            }
        }
        return null;
    }

    @Override
    public CommonFile addFileInfo4UE(HttpServletRequest request, MultipartFile file) throws Exception {
        SysUserExt opUser = this.getUser(request);
        String associateBizTable = request.getParameter("associate_biz_table");
        String associateBizSid = request.getParameter("associate_biz_sid");
        String associateBizFieldTag = request.getParameter("associate_biz_field_tag");
        String bizType = request.getParameter("biz_type");
        String accountSetSid =  HttpUtil.getAccountSet(request);
        String bizPath = bizType;
        if (HlpUtils.isEmpty(bizPath)) {
            bizPath = "default";
        }
        String filePath = this.getFilePath2Save4AccountSet(accountSetSid, bizPath, file.getOriginalFilename());
        File targetFile = new File(filePath);
        file.transferTo(targetFile);
        CommonFile commonFile = new CommonFile();
        if (opUser != null) {
            commonFile.setOwner_sid(opUser.getSid());
        }
        commonFile.setBiz_type(bizType);
        commonFile.setFile_path(targetFile.getAbsolutePath());
        commonFile.setOriginal_file_name(file.getOriginalFilename());
        commonFile.setAssociate_biz_field_tag(associateBizFieldTag);
        commonFile.setAssociate_biz_sid(associateBizSid);
        commonFile.setAssociate_biz_table(associateBizTable);
        commonFile.setState(HlpUtils.isEmpty(accountSetSid) ? CommonFileExt.StateNotUsed : CommonFileExt.StateUsed);
        this.saveCommonFile(commonFile, opUser);
        String urlPrefix = Config.getParameterValue(ConfigKeyConstants.UPLOAD_FILE_URL_PREFIX);
        String webUrl = urlPrefix + "file/file/";
        if (!HlpUtils.isEmpty(accountSetSid)) {
            webUrl += accountSetSid + "/";
        }
        webUrl += commonFile.getSid();
        commonFile.setWeb_url(webUrl);
        commonFileMapper.updateByPrimaryKeySelective(commonFile);
        return commonFile;
    }

    @Override
    public CommonFile addBase64FileInfo4UE(HttpServletRequest request, String base64) throws Exception {
        SysUserExt opUser = this.getUser(request);
        String associateBizTable = request.getParameter("associate_biz_table");
        String associateBizSid = request.getParameter("associate_biz_sid");
        String associateBizFieldTag = request.getParameter("associate_biz_field_tag");
        String bizType = request.getParameter("biz_type");
        String accountSetSid =  HttpUtil.getAccountSet(request);
        String bizPath = bizType;
        if (HlpUtils.isEmpty(bizPath)) {
            bizPath = "default";
        }
        String ext = FileUtil.getBase64FileType(base64);
        String datetimeFormatter4FileName = HlpUtils.date2String(new Date(), HlpUtils.Format_Yyyy_MM_dd_HH_mm_ss_FileName);
        String destFileName = datetimeFormatter4FileName + Math.random() + "." + ext;
        String filePath = this.getFilePath2Save4AccountSet(accountSetSid, bizPath, destFileName);
        File targetFile = new File(filePath);
        if (!targetFile.exists()) {
            targetFile.getParentFile().mkdirs();
            targetFile.createNewFile();
        }
        FileUtil.base64ToFile(base64, targetFile.getAbsolutePath());

        CommonFile commonFile = new CommonFile();
        if (opUser != null) {
            commonFile.setOwner_sid(opUser.getSid());
        }
        commonFile.setBiz_type(bizType);
        commonFile.setFile_path(targetFile.getAbsolutePath());
        commonFile.setOriginal_file_name(destFileName);
        commonFile.setAssociate_biz_field_tag(associateBizFieldTag);
        commonFile.setAssociate_biz_sid(associateBizSid);
        commonFile.setAssociate_biz_table(associateBizTable);
        commonFile.setState(HlpUtils.isEmpty(accountSetSid) ? CommonFileExt.StateNotUsed : CommonFileExt.StateUsed);
        this.saveCommonFile(commonFile, opUser);
        String urlPrefix = Config.getParameterValue(ConfigKeyConstants.UPLOAD_FILE_URL_PREFIX);
        String webUrl = urlPrefix + "file/file/";
        if (!HlpUtils.isEmpty(accountSetSid)) {
            webUrl += accountSetSid + "/";
        }
        webUrl += commonFile.getSid();
        commonFile.setWeb_url(webUrl);
        commonFileMapper.updateByPrimaryKeySelective(commonFile);
        return commonFile;
    }

    @Override
    public void deleteCommonFile(SysUser opUser, String sid) throws Exception {
        CommonFileExt old = commonFileMapper.selectBySid(sid);
        if (old != null) {
            super.autoInjectBaseData(old, opUser, TYPE_DELETE);
            commonFileMapper.updateByPrimaryKey(old);
        }
    }

    private SysUserExt getUser(HttpServletRequest request) throws Exception {
        String token = request.getHeader(Constants.REQ_HEADER_NAME_TOKEN);
        if (HlpUtils.isEmpty(token)) {
            token = request.getParameter(Constants.REQ_HEADER_NAME_TOKEN);
        }
        Claims claims = JwtRefreshUtil.getToken(token);
        if (claims != null) {
            return SysUtil.getSysUserFromClaims(claims);
        }
        return null;
    }


    private String getFilePath2Save4AccountSet(String accountSetSid, String bizPath, String originalFilename) {
        return getFilePath2Save(HlpUtils.isEmpty(accountSetSid) ? bizPath : accountSetSid + "/" + bizPath, originalFilename);
    }

    /**
     * 根据源名称得到需要保存的目标文件路径吗,会保留原名，如果存在重名的，则则后缀之前加上1，2，...的序号
     *
     * @param bizPath          页面路径，账套id+业务类型
     * @param originalFileName 源文件名
     * @return
     */
    public String getFilePath2Save(String bizPath, String originalFileName) {
        // 上传的根目录
        String rootPath = Config.getParameterValue(ConfigKeyConstants.UPLOAD_ROOT_PATH);
        // 上传文件在web访问时的ulr前缀
        String urlPrefix = Config.getParameterValue(ConfigKeyConstants.UPLOAD_FILE_URL_PREFIX);
        Calendar cal = Calendar.getInstance();
        int year = cal.get(Calendar.YEAR);
        int month = cal.get(Calendar.MONTH) + 1;
        int day = cal.get(Calendar.DAY_OF_MONTH);
        String midPath = File.separator + bizPath + File.separator + year + File.separator + month + File.separator + day;
        File rootAndMidPathFile = new File(rootPath + midPath);
        if (!rootAndMidPathFile.exists()) {
            rootAndMidPathFile.mkdirs();
        }
        String extWithDot = FileUtil.getFileType(originalFileName);
        String name = FileUtil.getFileNameWithoutExt(originalFileName);
        String destFileName = originalFileName;
        int index = 1;
        while (FileUtil.isFileExist(rootAndMidPathFile.getAbsolutePath() + File.separator + destFileName)) {
            destFileName = name + "_" + index + extWithDot;
            index++;
        }
        File targetFile = new File(rootAndMidPathFile, destFileName);
        return targetFile.getAbsolutePath();
    }
}
